#include <RSLib/Common.hpp>
#ifndef RSLIB___MATH_3D_HPP
#define RSLIB___MATH_3D_HPP
 
 
 
//---INCLUDE
//----------------------->
#include <RSLib/Types.hpp>
#include <RSLib/Math.hpp>
 
 
namespace RSLib{
namespace Math{
 
 
 
template<typename T = float> class Vector2
{
public:
	union	{
		struct{T x; T y;};
		T e[2];
	};
	
public:
	Vector2(){}
	Vector2(const T& f_) : x(f_),y(f_){}
	Vector2(const T& x_, const T& y_) : x(x_),y(y_){}
	
public:
	template<typename U> operator Vector2<U>(){return Vector2<U>( U(x), U(y) );}
};
 
 
 
template<typename T = float> class Vector3
{
public:
	union	{
		union {
			struct{T x; union{struct{Vector2<T> yz;}; T y;}; };
			struct{Vector2<T> xy; T z;};
		};
		T e[3];
	};
	
public:
	Vector3(){}
	Vector3(const T& f_) : x(f_),y(f_),z(f_){}
	Vector3(const T& x_, const T& y_, const T& z_) : x(x_),y(y_),z(z_){}
	
public:
	template<typename U> operator Vector3<U>(){return Vector3<U>( U(x), U(y), U(z) );}
};


template <typename T = float> class Vector4
{
public:
	union {
		struct{
			T x;
			union {
				struct{Vector2<T> yz;};
				struct{Vector3<T> yzw;};
				struct{T y; Vector2<T> zw;};
			};
		};
		
		struct{
			union{
				struct{Vector2<T> xy; T z;};
				struct{Vector3<T> xyz;};
			};
			T w;
		};		
		T e[4];
	};
	
public:
	Vector4(){}
	Vector4(const T& f_) : x(f_),y(f_),z(f_),w(f_){}
	Vector4(const T& x_, const T& y_, const T& z_, const T& w_) : x(x_),y(y_),z(z_),w(w_){}
	
public:
	template<typename U> operator Vector4<U>(){return Vector4<U>( U(x), U(y), U(z), U(w) );}
};
 
 
template<typename T = float> class Matrix3x3
{
public:
	union {
		struct{T e00,e01,e02,
					e10,e11,e12,
					e20,e21,e22;};
	T e[3][3];
	};
	
public:
	Matrix3x3(){}
	Matrix3x3(const T& e00_, const T& e01_, const T& e02_,
				 const T& e10_, const T& e11_, const T& e12_,
				 const T& e20_, const T& e21_, const T& e22_) :
				 e00(e00_), e01(e01_), e02(e02_),
				 e10(e10_), e11(e11_), e12(e12_),
				 e20(e20_), e21(e21_), e22(e22_){}
};
template<typename T = float> class Matrix4x4
{
public:
	union {
		struct{
			union{ struct{T e00,e01,e02,e03;}; struct{Vector4<T> r0;}; };
			union{ struct{T e10,e11,e12,e13;}; struct{Vector4<T> r1;}; };
			union{ struct{T e20,e21,e22,e23;}; struct{Vector4<T> r2;}; };
			union{ struct{T e30,e31,e32,e33;}; struct{Vector4<T> r3;}; };
		};
	T e[4][4];
	struct{Vector4<T>r[4];};
	};
	
	
public:
	Matrix4x4(){}
	Matrix4x4(const T& e00_, const T& e01_, const T& e02_, const T& e03_,
				 const T& e10_, const T& e11_, const T& e12_, const T& e13_,
				 const T& e20_, const T& e21_, const T& e22_, const T& e23_,
				 const T& e30_, const T& e31_, const T& e32_, const T& e33_) :
				 e00(e00_), e01(e01_), e02(e02_), e03(e03_),
				 e10(e10_), e11(e11_), e12(e12_), e13(e13_),
				 e20(e20_), e21(e21_), e22(e22_), e23(e23_),
				 e30(e30_), e31(e31_), e32(e32_), e33(e33_){}
};
 
 
 
template<typename T> inline Vector3<T> operator+(const Vector3<T>& a, const Vector3<T>& b)		{return Vector3<T>(a.x+b.x, a.y+b.y, a.z+b.z);}
template<typename T> inline Vector3<T> operator-(const Vector3<T>& a, const Vector3<T>& b)		{return Vector3<T>(a.x-b.x, a.y-b.y, a.z-b.z);}
template<typename T> inline Vector3<T> operator*(const Vector3<T>& a, const Vector3<T>& b)		{return Vector3<T>(a.x*b.x, a.y*b.y, a.z*b.z);} 
template<typename T> inline Vector3<T> operator/(const Vector3<T>& a, const Vector3<T>& b)		{return Vector3<T>(a.x/b.x, a.y/b.y, a.z/b.z);} 

template<typename T> inline Vector3<T> operator*(const T& f, const Vector3<T>& a)					{return Vector3<T>(f*a.x, f*a.y, f*a.z);}
template<typename T> inline Vector3<T> operator*(const Vector3<T>& a, const T& f)					{return Vector3<T>(a.x*f, a.y*f, a.z*f);}
template<typename T> inline Vector3<T> operator/(const Vector3<T>& a, const T& f)					{return Vector3<T>(a.x/f, a.y/f, a.z/f);}
template<typename T> inline Vector3<T> operator/(const T& f, const Vector3<T>& a)					{return Vector3<T>(f/a.x, f/a.y, f/a.z);}

template<typename T> inline Boolean operator == (const Vector3<T>& a, const Vector3<T>& b)		{return ( (a.x == b.x) && (a.y == b.y) && (a.z == b.z) );}
template<typename T> inline Boolean operator != (const Vector3<T>& a, const Vector3<T>& b)		{return ( (a.x != b.x) || (a.y != b.y) || (a.z != b.z) );}
 
template<typename T> inline Vector3<T> operator + (const Vector3<T>& a)									{return a;}
template<typename T> inline Vector3<T> operator - (const Vector3<T>& a)									{return Vector3<T>(-a.x,-a.y,-a.z);}
 
template<typename T> inline Vector4<T> operator , (const Vector3<T>& v, const T& f)					{return Vector4<T>(v.x,v.y,v.z,f);} 

template<typename T> inline void operator *= (Vector3<T>& a, const T& f)								{a.x*= f; a.y*= f;a.z*=f;}
template<typename T> inline void operator /= (Vector3<T>& a, const T& f)								{a.x/= f; a.y/= f;a.z/=f;}
template<typename T> inline void operator += (Vector3<T>& a, const Vector3<T>& b)					{a.x+= b.x; a.y+= b.y; a.z+=b.z;}
template<typename T> inline void operator -= (Vector3<T>& a, const Vector3<T>& b)					{a.x-= b.x; a.y-= b.y; a.z-=b.z;}
template<typename T> inline void operator *= (Vector3<T>& a, const Vector3<T>& b)					{a.x*= b.x; a.y*= b.y; a.z*=b.z;}
template<typename T> inline void operator /= (Vector3<T>& a, const Vector3<T>& b)					{a.x/= b.x; a.y/= b.y; a.z/=b.z;}
 
 
 
template<typename T> Vector3<T> Clamp(const Vector3<T>& v, const Vector3<T>& min, const Vector3<T>& max)
{
	return Vector3<T>( MIN(max.x,MAX(min.x,v.x)) , MIN(max.y,MAX(min.y,v.y)) , MIN(max.z,MAX(min.z,v.z)) );
}
template<typename T> T Length(const Vector3<T>& v)
{
	return SquareRoot(v.x*v.x+v.y*v.y+v.z*v.z);
}
 
 
template <typename T> Matrix3x3<T> operator*(const Matrix3x3<T>& A, const Matrix3x3<T>& B)
{
	return Matrix3x3<T>(	A.e00*B.e00 + A.e01*B.e10 + A.e02*B.e20,	A.e00*B.e01 + A.e01*B.e11 + A.e02*B.e21,	A.e00*B.e02 + A.e01*B.e12 + A.e02*B.e22,
								A.e10*B.e00 + A.e11*B.e10 + A.e12*B.e20,	A.e10*B.e01 + A.e11*B.e11 + A.e12*B.e21,	A.e10*B.e02 + A.e11*B.e12 + A.e12*B.e22,
								A.e20*B.e00 + A.e21*B.e10 + A.e22*B.e20,	A.e20*B.e01 + A.e21*B.e11 + A.e22*B.e21,	A.e20*B.e02 + A.e21*B.e12 + A.e22*B.e22 );
}
 
 
 
}//namespace Math
 
 
 
//---ALIASES
//---------------------------->
typedef Math::Vector2<int> int2;
typedef Math::Vector2<float> float2;
typedef Math::Vector3<float> float3;
typedef Math::Vector4<float> float4;
//typedef Matrix2x2<float> float2x2;
typedef Math::Matrix3x3<float> float3x3;
typedef Math::Matrix4x4<float> float4x4;
 
 
 
}//namespace RSLib
 
 
 
#endif//RSLIB___MATH_3D_HPP
